home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-27 | 66.9 KB | 1,875 lines | [TEXT/ROSA] |
- Common Lisp the Language, 2nd Edition
- -------------------------------------------------------------------------------
-
- 26. Loop
-
- By Jon L White
-
- [change_begin]
- PREFACE: X3J13 voted in January 1989 (LOOP-FACILITY) to adopt an extended
- definition of the loop macro as a part of the forthcoming draft Common Lisp
- standard.
-
- This chapter presents the bulk of the Common Lisp Loop Facility proposal,
- written by Jon L White. I have edited it only very lightly to conform to the
- overall style of this book and have inserted a small number of bracketed
- remarks, identified by the initials GLS. (See the Acknowledgments to this
- second edition for acknowledgments to others who contributed to the Loop
- Facility proposal.)
-
- - Guy L. Steele Jr.
-
- [change_end]
- -------------------------------------------------------------------------------
-
- * Introduction
- * How the Loop Facility Works
- * Parsing Loop Clauses
- o Order of Execution
- o Kinds of Loop Clauses
- o Loop Syntax
- * User Extensibility
- * Loop Constructs
- * Iteration Control
- * End-Test Control
- * Value Accumulation
- * Variable Initializations
- * Conditional Execution
- * Unconditional Execution
- * Miscellaneous Features
- o Data Types
- o Destructuring
-
- -------------------------------------------------------------------------------
-
- 26.1. Introduction
-
- [change_begin]
- A loop is a series of expressions that are executed one or more times, a
- process known as iteration. The Loop Facility defines a variety of useful
- methods, indicated by loop keywords, to iterate and to accumulate values in a
- loop.
-
- Loop keywords are not true Common Lisp keywords; they are symbols that are
- recognized by the Loop Facility and that provide such capabilities as
- controlling the direction of iteration, accumulating values inside the body of
- a loop, and evaluating expressions that precede or follow the loop body. If you
- do not use any loop keywords, the Loop Facility simply executes the loop body
- repeatedly.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.2. How the Loop Facility Works
-
- [change_begin]
- The driving element of the Loop Facility is the loop macro. When Lisp
- encounters a loop macro call form, it invokes the Loop Facility and passes to
- it the loop clauses as a list of unevaluated forms, as with any macro. The loop
- clauses contain Common Lisp forms and loop keywords. The loop keywords are
- recognized by their symbol name, regardless of the packages that contain them.
- The loop macro translates the given form into Common Lisp code and returns the
- expanded form.
-
- The expanded loop form is one or more lambda-expressions for the local binding
- of loop variables and a block and a tagbody that express a looping control
- structure. The variables established in the loop construct are bound as if by
- using let or lambda. Implementations can interleave the setting of initial
- values with the bindings. However, the assignment of the initial values is
- always calculated in the order specified by the user. A variable is thus
- sometimes bound to a harmless value of the correct data type, and then later in
- the prologue it is set to the true initial value by using setq.
-
- The expanded form consists of three basic parts in the tagbody:
-
- * The loop prologue contains forms that are executed before iteration
- begins, such as initial settings of loop variables and possibly an initial
- termination test.
-
- * The loop body contains those forms that are executed during iteration,
- including application-specific calculations, termination tests, and
- variable stepping. Stepping is the process of assigning a variable the
- next item in a series of items.
-
- * The loop epilogue contains forms that are executed after iteration
- terminates, such as code to return values from the loop.
-
- Expansion of the loop macro produces an implicit block (named nil). Thus, the
- Common Lisp macro return and the special form return-from can be used to return
- values from a loop or to exit a loop.
-
- Within the executable parts of loop clauses and around the entire loop form,
- you can still bind variables by using the Common Lisp special form let.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.3. Parsing Loop Clauses
-
- [change_begin]
- The syntactic parts of a loop construct are called clauses; the scope of each
- clause is determined by the top-level parsing of that clause's keyword. The
- following example shows a loop construct with six clauses:
-
- (loop for i from 1 to (compute-top-value) ;First clause
- while (not (unacceptable i)) ;Second clause
- collect (square i) ;Third clause
- do (format t "Working on ~D now" i) ;Fourth clause
- when (evenp i) ;Fifth clause
- do (format t "~D is a non-odd number" i)
- finally (format t "About to exit!")) ;Sixth clause
-
- Each loop keyword introduces either a compound loop clause or a simple loop
- clause that can consist of a loop keyword followed by a single Lisp form. The
- number of forms in a clause is determined by the loop keyword that begins the
- clause and by the auxiliary keywords in the clause. The keywords do, initially,
- and finally are the only loop keywords that can take any number of Lisp forms
- and group them as if in a single progn form.
-
- Loop clauses can contain auxiliary keywords, which are sometimes called
- prepositions. For example, the first clause in the preceding code includes the
- prepositions from and to, which mark the value from which stepping begins and
- the value at which stepping ends.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- * Order of Execution
- * Kinds of Loop Clauses
- * Loop Syntax
-
- -------------------------------------------------------------------------------
-
- 26.3.1. Order of Execution
-
- [change_begin]
- With the exceptions listed below, clauses are executed in the loop body in the
- order in which they appear in the source. Execution is repeated until a clause
- terminates the loop or until a Common Lisp return, go, or throw form is
- encountered. The following actions are exceptions to the linear order of
- execution:
-
- * All variables are initialized first, regardless of where the establishing
- clauses appear in the source. The order of initialization follows the
- order of these clauses.
-
- * The code for any initially clauses is collected into one progn in the
- order in which the clauses appear in the source. The collected code is
- executed once in the loop prologue after any implicit variable
- initializations.
-
- * The code for any finally clauses is collected into one progn in the order
- in which the clauses appear in the source. The collected code is executed
- once in the loop epilogue before any implicit values from the accumulation
- clauses are returned. Explicit returns anywhere in the source, however,
- will exit the loop without executing the epilogue code.
-
- * A with clause introduces a variable binding and an optional initial
- value. The initial values are calculated in the order in which the with
- clauses occur.
-
- * Iteration control clauses implicitly perform the following actions:
-
- o initializing variables
-
- o stepping variables, generally between each execution of the loop
- body
-
- o performing termination tests, generally just before the execution of
- the loop body
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.3.2. Kinds of Loop Clauses
-
- [change_begin]
- Loop clauses fall into one of the following categories:
-
- * variable initialization and stepping
-
- o The for and as constructs provide iteration control clauses that
- establish a variable to be initialized. You can combine for and as
- clauses with the loop keyword and to get parallel initialization and
- stepping.
-
- o The with construct is similar to a single let clause. You can
- combine with clauses using and to get parallel initialization.
-
- o The repeat construct causes iteration to terminate after a specified
- number of times. It uses an internal variable to keep track of the
- number of iterations.
-
- You can specify data types for loop variables (see section 26.12.1). It is
- an error to bind the same variable twice in any variable-binding clause of
- a single loop expression. Such variables include local variables,
- iteration control variables, and variables found by destructuring.
-
- * value accumulation
-
- o The collect construct takes one form in its clause and adds the
- value of that form to the end of a list of values. By default, the
- list of values is returned when the loop finishes.
-
- o The append construct takes one form in its clause and appends the
- value of that form to the end of a list of values. By default, the
- list of values is returned when the loop finishes.
-
- o The nconc construct is similar to append, but its list values are
- concatenated as if by the Common Lisp function nconc. By default, the
- list of values is returned when the loop finishes.
-
- o The sum construct takes one form in its clause that must evaluate to
- a number and adds that number into a running total. By default, the
- cumulative sum is returned when the loop finishes.
-
- o The count construct takes one form in its clause and counts the
- number of times that the form evaluates to a non-nil value. By
- default, the count is returned when the loop finishes.
-
- o The minimize construct takes one form in its clause and determines
- the minimum value obtained by evaluating that form. By default, the
- minimum value is returned when the loop finishes.
-
- o The maximize construct takes one form in its clause and determines
- the maximum value obtained by evaluating that form. By default, the
- maximum value is returned when the loop finishes.
-
- * termination conditions
-
- o The loop-finish Lisp macro terminates iteration and returns any
- accumulated result. If specified, any finally clauses are evaluated.
-
- o The for and as constructs provide a termination test that is
- determined by the iteration control clause.
-
- o The repeat construct causes termination after a specified number of
- iterations.
-
- o The while construct takes one form, a condition, and terminates the
- iteration if the condition evaluates to nil. A while clause is
- equivalent to the expression (if (not condition) (loop-finish)).
-
- o The until construct is the inverse of while; it terminates the
- iteration if the condition evaluates to any non-nil value. An until
- clause is equivalent to the expression (if condition (loop-finish)).
-
- o The always construct takes one form and terminates the loop if the
- form ever evaluates to nil; in this case, it returns nil. Otherwise,
- it provides a default return value of t.
-
- o The never construct takes one form and terminates the loop if the
- form ever evaluates to non-nil; in this case, it returns nil.
- Otherwise, it provides a default return value of t.
-
- o The thereis construct takes one form and terminates the loop if the
- form ever evaluates to non-nil; in this case, it returns that value.
-
- * unconditional execution
-
- o The do construct simply evaluates all forms in its clause.
-
- o The return construct takes one form and returns its value. It is
- equivalent to the clause do (return value).
-
- * conditional execution
-
- o The if construct takes one form as a predicate and a clause that is
- executed when the predicate is true. The clause can be a value
- accumulation, unconditional, or another conditional clause; it can
- also be any combination of such clauses connected by the loop keyword
- and.
-
- o The when construct is a synonym for if.
-
- o The unless construct is similar to when except that it complements
- the predicate; it executes the following clause if the predicate is
- false.
-
- o The else construct provides an optional component of if, when, and
- unless clauses that is executed when the predicate is false. The
- component is one of the clauses described under if.
-
- o The end construct provides an optional component to mark the end of
- a conditional clause.
-
- * miscellaneous operations
-
- o The named construct assigns a name to a loop construct.
-
- o The initially construct causes its forms to be evaluated in the loop
- prologue, which precedes all loop code except for initial settings
- specified by the constructs with, for, or as.
-
- o The finally construct causes its forms to be evaluated in the loop
- epilogue after normal iteration terminates. An unconditional clause
- can also follow the loop keyword finally.
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.3.3. Loop Syntax
-
- [change_begin]
- The following syntax description provides an overview of the syntax for loop
- clauses. Detailed syntax descriptions of individual clauses appear in sections
- 26.6 through 26.12. A loop consists of the following types of clauses:
-
- initial-final ::= initially | finally
- variables ::= with | initial-final | for-as | repeat
- main ::= unconditional | accumulation | conditional
- | termination | initial-final
- loop ::= (loop [named name] {variables}* {main}*)
-
- Note that a loop must have at least one clause; however, for backward
- compatibility, the following format is also supported:
-
- (loop {tag | expr}*)
-
- where expr is any Common Lisp expression that can be evaluated, and tag is any
- symbol not identifiable as a loop keyword. Such a format is roughly equivalent
- to the following one:
-
- (loop do {tag | expr}*)
-
- A loop prologue consists of any automatic variable initializations prescribed
- by the variable clauses, along with any initially clauses in the order they
- appear in the source.
-
- A loop epilogue consists of finally clauses, if any, along with any implicit
- return value from an accumulation clause or an end-test clause.
-
- [change_end]
- -------------------------------------------------------------------------------
-
- 26.4. User Extensibility
-
- [change_begin]
- There is currently no specified portable method for users to add extensions to
- the Loop Facility. The names defloop and define-loop-method have been suggested
- as candidates for such a method.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.5. Loop Constructs
-
- [change_begin]
- The remaining sections of this chapter describe the constructs that the Loop
- Facility provides. The descriptions are organized according to the
- functionality of the constructs. Each section begins with a general discussion
- of a particular operation; it then presents the constructs that perform the
- operation.
-
- * Section 26.6, ``Iteration Control,'' describes iteration control clauses
- that allow directed loop iteration.
-
- * Section 26.7, ``End-Test Control,'' describes clauses that stop iteration
- by providing a conditional expression that can be tested after each
- execution of the loop body.
-
- * Section 26.8, ``Value Accumulation,'' describes constructs that
- accumulate values during iteration and return them from a loop. This
- section also discusses ways in which accumulation clauses can be combined
- within the Loop Facility.
-
- * Section 26.9, ``Variable Initializations,'' describes the with construct,
- which provides local variables for use within the loop body, and other
- constructs that provide local variables.
-
- * Section 26.10, ``Conditional Execution,'' describes how to execute loop
- clauses conditionally.
-
- * Section 26.11, ``Unconditional Execution,'' describes the do and return
- constructs. It also describes constructs that are used in the loop
- prologue and loop epilogue.
-
- * Section 26.12, ``Miscellaneous Features,'' discusses loop data types and
- destructuring. It also presents constructs for naming a loop and for
- specifying initial and final actions.
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.6. Iteration Control
-
- [change_begin]
- Iteration control clauses allow you to direct loop iteration. The loop keywords
- as, for, and repeat designate iteration control clauses.
-
- Iteration control clauses differ with respect to the specification of
- termination conditions and the initialization and stepping of loop variables.
- Iteration clauses by themselves do not cause the Loop Facility to return
- values, but they can be used in conjunction with value-accumulation clauses to
- return values (see section 26.8).
-
- All variables are initialized in the loop prologue. The scope of the variable
- binding is lexical unless it is proclaimed special; thus, the variable can be
- accessed only by expressions that lie textually within the loop. Stepping
- assignments are made in the loop body before any other expressions are
- evaluated in the body.
-
- The variable argument in iteration control clauses can be a destructuring list.
- A destructuring list is a tree whose non-null atoms are symbols that can be
- assigned a value (see section 26.12.2).
-
- The iteration control clauses for, as, and repeat must precede any other loop
- clauses except initially, with, and named, since they establish variable
- bindings. When iteration control clauses are used in a loop, termination tests
- in the loop body are evaluated before any other loop body code is executed.
-
- If you use multiple iteration clauses to control iteration, variable
- initialization and stepping occur sequentially by default. You can use the and
- construct to connect two or more iteration clauses when sequential binding and
- stepping are not necessary. The iteration behavior of clauses joined by and is
- analogous to the behavior of the Common Lisp macro do relative to do*.
-
- [X3J13 voted in March 1989 (LOOP-AND-DISCREPANCY) to correct a minor
- inconsistency in the original syntactic specification for loop. Only for and as
- clauses (not repeat clauses) may be joined by the and construct. The precise
- syntax is as follows.
-
- for-as ::= {for | as} for-as-subclause {and for-as-subclause}*
- for-as-subclause ::= for-as-arithmetic | for-as-in-list
- | for-as-on-list | for-as-equals-then
- | for-as-across | for-as-hash | for-as-package
- for-as-arithmetic ::= var [type-spec] [{from | downfrom | upfrom} expr1 ]
- [{to | downto | upto | below | above} expr2]
- [by expr3]
- for-as-in-list ::= var [type-spec] in expr1 [by step-fun]
- for-as-on-list ::= var [type-spec] on expr1 [by step-fun]
- for-as-equals-then ::= var [type-spec] = expr1 [then step-fun]
- for-as-across ::= var [type-spec] across vector
- for-as-hash ::= var [type-spec] being {each | the}
- {hash-key | hash-keys | hash-value | hash-values}
- {in | of} hash-table
- [using ({hash-value | hash-key} other-var)]
- for-as-package ::= var [type-spec] being {each | the}
- for-as-package-keyword
- {in | of} package
- for-as-package-keyword ::= symbol | present-symbol | external-symbol
- | symbols | present-symbols | external-symbols
-
- This correction made for and as clauses syntactically similar to with clauses.
- I have changed all examples in this chapter to reflect the corrected
- syntax.-GLS]
-
- In the following example, the variable x is stepped before y is stepped; thus,
- the value of y reflects the updated value of x:
-
- (loop for x from 1 to 9
- for y = nil then x
- collect (list x y))
- => ((1 NIL) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9))
-
- In the following example, x and y are stepped in parallel:
-
- (loop for x from 1 to 9
- and y = nil then x
- collect (list x y))
- => ((1 NIL) (2 1) (3 2) (4 3) (5 4) (6 5) (7 6) (8 7) (9 8))
-
- The for and as clauses iterate by using one or more local loop variables that
- are initialized to some value and that can be modified or stepped after each
- iteration. For these clauses, iteration terminates when a local variable
- reaches some specified value or when some other loop clause terminates
- iteration. At each iteration, variables can be stepped by an increment or a
- decrement or can be assigned a new value by the evaluation of an expression.
- Destructuring can be used to assign initial values to variables during
- iteration.
-
- The for and as keywords are synonyms and may be used interchangeably. There are
- seven syntactic representations for these constructs. In each syntactic
- description, the data type of var can be specified by the optional type-spec
- argument. If var is a destructuring list, the data type specified by the
- type-spec argument must appropriately match the elements of the list (see
- sections 26.12.1 and 26.12.2).
-
- [Loop Clause]
-
- for var [type-spec] [{from | downfrom | upfrom} expr1]
- [{to | downto | upto | below | above} expr2]
- [by expr3]
- as var [type-spec] [{from | downfrom | upfrom} expr1]
- [{to | downto | upto | below | above} expr2]
- [by expr3]
-
- [This is the first of seven for/as syntaxes.-GLS]
-
- The for or as construct iterates from the value specified by expr1 to the value
- specified by expr2 in increments or decrements denoted by expr3. Each
- expression is evaluated only once and must evaluate to a number.
-
- The variable var is bound to the value of expr1 in the first iteration and is
- stepped by the value of expr3 in each succeeding iteration, or by 1 if expr3 is
- not provided.
-
- The following loop keywords serve as valid prepositions within this syntax.
-
- from
- The loop keyword from marks the value from which stepping begins, as
- specified by expr1. Stepping is incremental by default. For decremental
- stepping, use above or downto with expr2. For incremental stepping, the
- default from value is 0.
-
- downfrom, upfrom
- The loop keyword downfrom indicates that the variable var is decreased in
- decrements specified by expr3; the loop keyword upfrom indicates that var
- is increased in increments specified by expr3.
-
- to The loop keyword to marks the end value for stepping specified in expr2.
- Stepping is incremental by default. For decremental stepping, use downto,
- downfrom, or above with expr2.
-
- downto, upto
- The loop keyword downto allows iteration to proceed from a larger number
- to a smaller number by the decrement expr3. The loop keyword upto allows
- iteration to proceed from a smaller number to a larger number by the
- increment expr3. Since there is no default for expr1 in decremental
- stepping, you must supply a value with downto.
-
- below, above
- The loop keywords below and above are analogous to upto and downto,
- respectively. These keywords stop iteration just before the value of the
- variable var reaches the value specified by expr2; the end value of expr2
- is not included. Since there is no default for expr1 in decremental
- stepping, you must supply a value with above.
-
- by The loop keyword by marks the increment or decrement specified by expr3.
- The value of expr3 can be any positive number. The default value is 1.
-
- At least one of these prepositions must be used with this syntax.
-
- In an iteration control clause, the for or as construct causes termination when
- the specified limit is reached. That is, iteration continues until the value
- var is stepped to the exclusive or inclusive limit specified by expr2. The
- range is exclusive if expr3 increases or decreases var to the value of expr2
- without reaching that value; the loop keywords below and above provide
- exclusive limits. An inclusive limit allows var to attain the value of expr2;
- to, downto, and upto provide inclusive limits.
-
- A common convention is to use for to introduce new iterations and as to
- introduce iterations that depend on a previous iteration specification.
- [However, loop does not enforce this convention, and some of the examples below
- violate it. De gustibus non disputandum est.-GLS]
-
- Examples:
-
- ;;; Print some numbers.
-
- (loop as i from 1 to 5
- do (print i)) `;Prints 5 lines
-
-
-
-
-
- => NIL
-
- ;;; Print every third number.
-
- (loop for i from 10 downto 1 by 3
- do (print i)) `;Prints 4 lines
- 10
-
-
-
- => NIL
-
- ;;; Step incrementally from the default starting value.
-
- (loop as i below 5
- do (print i)) `;Prints 5 lines
-
-
-
-
-
- => NIL
-
- [Loop Clause]
- for var [type-spec] in expr1 [by step-fun]
- as var [type-spec] in expr1 [by step-fun]
-
- [This is the second of seven for/as syntaxes.-GLS]
-
- This construct iterates over the contents of a list. It checks for the end of
- the list as if using the Common Lisp function endp. The variable var is bound
- to the successive elements of the list expr1 before each iteration. At the end
- of each iteration, the function step-fun is called on the list and is expected
- to produce a successor list; the default value for step-fun is the cdr
- function.
-
- The for or as construct causes termination when the end of the list is reached.
- The loop keywords in and by serve as valid prepositions in this syntax.
-
- Examples:
-
- ;;; Print every item in a list.
-
- (loop for item in '(1 2 3 4 5) do (print item)) `;Prints 5 lines
-
-
-
-
-
- => NIL
-
- ;;; Print every other item in a list.
-
- (loop for item in '(1 2 3 4 5) by #'cddr
- do (print item)) `;Prints 3 lines
-
-
-
- => NIL
-
- ;;; Destructure items of a list, and sum the x values
- ;;; using fixnum arithmetic.
- (loop for (item . x) (t . fixnum)
- in '((A . 1) (B . 2) (C . 3))
- unless (eq item 'B) sum x)
- => 4
-
- [Loop Clause]
- for var [type-spec] on expr1 [by step-fun]
- as var [type-spec] on expr1 [by step-fun]
-
- [This is the third of seven for/as syntaxes.-GLS]
-
- This construct iterates over the contents of a list. It checks for the end of
- the list as if using the Common Lisp function endp. The variable var is bound
- to the successive tails of the list expr1. At the end of each iteration, the
- function step-fun is called on the list and is expected to produce a successor
- list; the default value for step-fun is the cdr function.
-
- The loop keywords on and by serve as valid prepositions in this syntax. The for
- or as construct causes termination when the end of the list is reached.
-
- Examples:
-
- ;;; Collect successive tails of a list.
- (loop for sublist on '(a b c d)
- collect sublist)
- => ((A B C D) (B C D) (C D) (D))
-
- ;;; Print a list by using destructuring with the loop keyword ON.
- (loop for (item) on '(1 2 3)
- do (print item)) `;Prints 3 lines
-
-
-
- => NIL
-
- ;;; Print items in a list without using destructuring.
- (loop for item in '(1 2 3)
- do (print item)) `;Prints 3 lines
-
-
-
- => NIL
-
- [Loop Clause]
- for var [type-spec] = expr1 [then expr2]
- as var [type-spec] = expr1 [then expr2]
-
- [This is the fourth of seven for/as syntaxes.-GLS]
-
- This construct initializes the variable var by setting it to the result of
- evaluating expr1 on the first iteration, then setting it to the result of
- evaluating expr2 on the second and subsequent iterations. If expr2 is omitted,
- the construct uses expr1 on the second and subsequent iterations. When expr2 is
- omitted, the expanded code shows the following optimization:
-
- ;;; Sample original code:
- (loop for x = expr1 then expr2 do (print x))
-
- ;;; The usual expansion:
- (tagbody
- (setq x expr1)
- tag (print x)
- (setq x expr2)
- (go tag))
-
- ;;; The optimized expansion:
- (tagbody
- tag (setq x expr1)
- (print x)
- (go tag))
-
- The loop keywords = and then serve as valid prepositions in this syntax. This
- construct does not provide any termination conditions.
-
- Example:
-
- ;;; Collect some numbers.
- (loop for item = 1 then (+ item 10)
- repeat 5
- collect item)
- => (1 11 21 31 41)
-
- [Loop Clause]
- for var [type-spec] across vector
- as var [type-spec] across vector
-
- [This is the fifth of seven for/as syntaxes.-GLS]
-
- This construct binds the variable var to the value of each element in the array
- vector.
-
- The loop keyword across marks the array vector; across is used as a preposition
- in this syntax. Iteration stops when there are no more elements in the
- specified array that can be referenced.
-
- Some implementations might use a [user-supplied-GLS] the special form in the
- vector form to produce more efficient code.
-
- Example:
-
- (loop for char across (the simple-string (find-message port))
- do (write-char char stream))
-
- [Loop Clause]
-
- for var [type-spec] being {each | the}
- {hash-key | hash-keys | hash-value | hash-values}
- {in | of} hash-table [using ({hash-value | hash-key} other-var)]
- as var [type-spec] being {each | the}
- {hash-key | hash-keys | hash-value | hash-values}
- {in | of} hash-table [using ({hash-value | hash-key} other-var)]
-
- [This is the sixth of seven for/as syntaxes.-GLS]
-
- This construct iterates over the elements, keys, and values of a hash table.
- The variable var takes on the value of each hash key or hash value in the
- specified hash table.
-
- The following loop keywords serve as valid prepositions within this syntax.
-
- being
- The keyword being marks the loop method to be used, either hash-key or
- hash-value.
-
- each, the
- For purposes of readability, the loop keyword each should follow the loop
- keyword being when hash-key or hash-value is used. The loop keyword the is
- used with hash-keys and hash-values.
-
- hash-key, hash-keys
- These loop keywords access each key entry of the hash table. If the name
- hash-value is specified in a using construct with one of these loop
- methods, the iteration can optionally access the keyed value. The order in
- which the keys are accessed is undefined; empty slots in the hash table
- are ignored.
-
- hash-value, hash-values
- These loop keywords access each value entry of a hash table. If the name
- hash-key is specified in a using construct with one of these loop methods,
- the iteration can optionally access the key that corresponds to the value.
- The order in which the keys are accessed is undefined; empty slots in the
- hash table are ignored.
-
- using
- The loop keyword using marks the optional key or the keyed value to be
- accessed. It allows you to access the hash key if iterating over the hash
- values, and the hash value if iterating over the hash keys.
-
- in, of
- These loop prepositions mark the hash table hash-table.
-
- Iteration stops when there are no more hash keys or hash values to be
- referenced in the specified hash table.
-
- [Loop Clause]
-
- for var [type-spec] being {each | the}
- {symbol | present-symbol | external-symbol |
- symbols | present-symbols | external-symbols}
- {in | of} package
- as var [type-spec] being {each | the}
- {symbol | present-symbol | external-symbol |
- symbols | present-symbols | external-symbols}
- {in | of} package
-
- [This is the last of seven for/as syntaxes.-GLS]
-
- This construct iterates over the symbols in a package. The variable var takes
- on the value of each symbol in the specified package.
-
- The following loop keywords serve as valid prepositions within this syntax.
-
- being
- The keyword being marks the loop method to be used: symbol,
- present-symbol, or external-symbol.
-
- each, the
- For purposes of readability, the loop keyword each should follow the loop
- keyword being when symbol, present-symbol, or external-symbol is used. The
- loop keyword the is used with symbols, present-symbols, and
- external-symbols.
-
- present-symbol, present-symbols
- These loop methods iterate over the symbols that are present but not
- external in a package. The package to be iterated over is specified in the
- same way that package arguments to the Common Lisp function find-package
- are specified. If you do not specify the package for the iteration, the
- current package is used. If you specify a package that does not exist, an
- error is signaled.
-
- symbol, symbols
- These loop methods iterate over symbols that are accessible from a given
- package. The package to be iterated over is specified in the same way that
- package arguments to the Common Lisp function find-package are specified.
- If you do not specify the package for the iteration, the current package
- is used. If you specify a package that does not exist, an error is
- signaled.
-
- external-symbol, external-symbols
- These loop methods iterate over the external symbols of a package. The
- package to be iterated over is specified in the same way that package
- arguments to the Common Lisp function find-package are specified. If you
- do not specify the package for the iteration, the current package is used.
- If you specify a package that does not exist, an error is signaled.
-
- in, of
- These loop prepositions mark the package package.
-
- Iteration stops when there are no more symbols to be referenced in the
- specified package.
-
- Example:
-
- (loop for x being each present-symbol of "COMMON-LISP-USER"
- do (print x)) `;Prints 7 lines in this example
- COMMON-LISP-USER::IN
- COMMON-LISP-USER::X
- COMMON-LISP-USER::ALWAYS
- COMMON-LISP-USER::FOO
- COMMON-LISP-USER::Y
- COMMON-LISP-USER::FOR
- COMMON-LISP-USER::LUCID
- => NIL
-
- [Loop Clause]
- repeat expr
-
- The repeat construct causes iteration to terminate after a specified number of
- times. The loop body is executed n times, where n is the value of the
- expression expr. The expr argument is evaluated one time in the loop prologue.
- If the expression evaluates to zero or to a negative number, the loop body is
- not evaluated.
-
- The clause repeat n is roughly equivalent to a clause such as
-
- for internal-variable downfrom (- n 1) to 0
-
- but, in some implementations, the repeat construct might be more efficient.
-
- Examples:
-
- (loop repeat 3 `;Prints 3 lines
- do (format t "What I say three times is true~%"))
- What I say three times is true
- What I say three times is true
- What I say three times is true
- => NIL
-
- (loop repeat -15 `;Prints nothing
- do (format t "What you see is what you expect~%"))
- => NIL
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.7. End-Test Control
-
- [change_begin]
- The loop keywords always, never, thereis, until, and while designate constructs
- that use a single test condition to determine when loop iteration should
- terminate.
-
- The constructs always, never, and thereis provide specific values to be
- returned when a loop terminates. Using always, never, or thereis with
- value-returning accumulation clauses can produce unpredictable results. In all
- other respects these constructs behave like the while and until constructs.
-
- The macro loop-finish can be used at any time to cause normal termination. In
- normal termination, finally clauses are executed and default return values are
- returned.
-
- End-test control constructs can be used anywhere within the loop body. The
- termination conditions are tested in the order in which they appear.
-
- [Loop Clause]
- while expr
- until expr
-
- The while construct allows iteration to continue until the specified expression
- expr evaluates to nil. The expression is re-evaluated at the location of the
- while clause.
-
- The until construct is equivalent to while (not expr). If the value of the
- specified expression is non-nil, iteration terminates.
-
- You can use while and until at any point in a loop. If a while or until clause
- causes termination, any clauses that precede it in the source are still
- evaluated.
-
- Examples:
-
- ;;; A classic "while-loop".
- (loop while (hungry-p) do (eat))
-
- ;;; UNTIL NOT is equivalent to WHILE.
- (loop until (not (hungry-p)) do (eat))
-
- ;;; Collect the length and the items of STACK.
- (let ((stack '(a b c d e f)))
- (loop while stack
- for item = (length stack) then (pop stack)
- collect item))
- => (6 A B C D E F)
-
- ;;; Use WHILE to terminate a loop that otherwise wouldn't
- ;;; terminate. Note that WHILE occurs after the WHEN.
- (loop for i fixnum from 3
- when (oddp i) collect i
- while (< i 5))
- => (3 5)
-
- [Loop Clause]
- always expr
- never expr
- thereis expr
-
- The always construct takes one form and terminates the loop if the form ever
- evaluates to nil; in this case, it returns nil. Otherwise, it provides a
- default return value of t.
-
- The never construct takes one form and terminates the loop if the form ever
- evaluates to non-nil; in this case, it returns nil. Otherwise, it provides a
- default return value of t.
-
- The thereis construct takes one form and terminates the loop if the form ever
- evaluates to non-nil; in this case, it returns that value.
-
- If the while or until construct causes termination, control is passed to the
- loop epilogue, where any finally clauses will be executed. Since always, never,
- and thereis use the Common Lisp macro return to terminate iteration, any
- finally clause that is specified is not evaluated.
-
- Examples:
-
- ;;; Make sure I is always less than 11 (two ways).
- ;;; The FOR construct terminates these loops.
-
- (loop for i from 0 to 10
- always (< i 11))
- => T
-
- (loop for i from 0 to 10
- never (> i 11))
- => T
-
- ;;; If I exceeds 10, return I; otherwise, return NIL.
- ;;; The THEREIS construct terminates this loop.
-
- (loop for i from 0
- thereis (when (> i 10) i) )
- => 11
-
- ;;; The FINALLY clause is not evaluated in these examples.
-
- (loop for i from 0 to 10
- always (< i 9)
- finally (print "you won't see this"))
- => NIL
-
- (loop never t
- finally (print "you won't see this"))
- => NIL
-
- (loop thereis "Here is my value"
- finally (print "you won't see this"))
- => "Here is my value"
-
- ;;; The FOR construct terminates this loop,
- ;;; so the FINALLY clause is evaluated.
-
- (loop for i from 1 to 10
- thereis (> i 11)
- finally (print i)) `;Prints 1 line
- 11
- => NIL
-
- (defstruct mountain height difficulty (why "because it is there"))
- (setq everest (make-mountain :height '(2.86e-13 parsecs)))
- (setq chocorua (make-mountain :height '(1059180001 microns)))
- (defstruct desert area (humidity 0))
- (setq sahara (make-desert :area '(212480000 square furlongs)))
- `;First there is a mountain, then there is no mountain, then there is ...
- (loop for x in (list everest sahara chocorua) `; -GLS
- thereis (and (mountain-p x) (mountain-height x)))
- => (2.86E-13 PARSECS)
-
- ;;; If you could use this code to find a counterexample to
- ;;; Fermat's last theorem, it would still not return the value
- ;;; of the counterexample because all of the THEREIS clauses
- ;;; in this example return only T. Of course, this code has
- ;;; never been observed to terminate.
-
- (loop for z upfrom 2
- thereis
- (loop for n upfrom 3 below (log z 2)
- thereis
- (loop for x below z
- thereis
- (loop for y below z
- thereis (= (+ (expt x n)
- (expt y n))
- (expt z n))))))
-
- [Macro]
- loop-finish
-
- The macro loop-finish terminates iteration normally and returns any accumulated
- result. If specified, a finally clause is evaluated.
-
- In most cases it is not necessary to use loop-finish because other loop control
- clauses terminate the loop. Use loop-finish to provide a normal exit from a
- nested condition inside a loop.
-
- You can use loop-finish inside nested Lisp code to provide a normal exit from a
- loop. Since loop-finish transfers control to the loop epilogue, using
- loop-finish within a finally expression can cause infinite looping.
-
- Implementations are allowed to provide this construct as a local macro by using
- macrolet.
-
- Examples:
-
- ;;; Print a date in February, but exclude leap day.
- ;;; LOOP-FINISH exits from the nested condition.
- (loop for date in date-list
- do (case date
- (29 (when (eq month 'february)
- (loop-finish))
- (format t "~:@(~A~) ~A" month date))))
-
- ;;; Terminate the loop, but return the accumulated count.
- (loop for i in '(1 2 3 stop-here 4 5 6)
- when (symbolp i) do (loop-finish)
- count i)
- => 3
-
- ;;; This loop works just as well as the previous example.
- (loop for i in '(1 2 3 stop-here 4 5 6)
- until (symbolp i)
- count i)
- => 3
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.8. Value Accumulation
-
- [change_begin]
- Accumulating values during iteration and returning them from a loop is often
- useful. Some of these accumulations occur so frequently that special loop
- clauses have been developed to handle them.
-
- The loop keywords append, appending, collect, collecting, nconc, and nconcing
- designate clauses that accumulate values in lists and return them.
-
- The loop keywords count, counting, maximize, maximizing, minimize, minimizing,
- sum, and summing designate clauses that accumulate and return numerical values.
- [There is no semantic difference between the ``ing'' keywords and their
- non-``ing'' counterparts. They are provided purely for the sake of stylistic
- diversity among users. I happen to prefer the non-``ing'' forms-when I use loop
- at all.-GLS]
-
- The loop preposition into can be used to name the variable used to hold partial
- accumulations. The variable is bound as if by the loop construct with (see
- section 26.9). If into is used, the construct does not provide a default return
- value; however, the variable is available for use in any finally clause.
-
- You can combine value-returning accumulation clauses in a loop if all the
- clauses accumulate the same type of data object. By default, the Loop Facility
- returns only one value; thus, the data objects collected by multiple
- accumulation clauses as return values must have compatible types. For example,
- since both the collect and append constructs accumulate objects into a list
- that is returned from a loop, you can combine them safely.
-
- ;;; Collect every name and the kids in one list by using
- ;;; COLLECT and APPEND.
- (loop for name in '(fred sue alice joe june)
- for kids in '((bob ken) () () (kris sunshine) ())
- collect name
- append kids)
- => (FRED BOB KEN SUE ALICE JOE KRIS SUNSHINE JUNE)
-
- [In the preceding example, note that the items accumulated by the collect and
- append clauses are interleaved in the result list, according to the order in
- which the clauses were executed.-GLS]
-
- Multiple clauses that do not accumulate the same type of data object can
- coexist in a loop only if each clause accumulates its values into a different
- user-specified variable. Any number of values can be returned from a loop if
- you use the Common Lisp function values, as the next example shows:
-
- ;;; Count and collect names and ages.
- (loop for name in '(fred sue alice joe june)
- as age in '(22 26 19 20 10)
- append (list name age) into name-and-age-list
- count name into name-count
- sum age into total-age
- finally
- (return (values (round total-age name-count)
- name-and-age-list)))
- => 19 and (FRED 22 SUE 26 ALICE 19 JOE 20 JUNE 10)
-
- [Loop Clause]
- collect expr [into var]
- collecting expr [into var]
-
- During each iteration, these constructs collect the value of the specified
- expression into a list. When iteration terminates, the list is returned.
-
- The argument var is set to the list of collected values; if var is specified,
- the loop does not return the final list automatically. If var is not specified,
- it is equivalent to specifying an internal name for var and returning its value
- in a finally clause. The var argument is bound as if by the construct with. You
- cannot specify a data type for var; it must be of type list.
-
- Examples:
-
- ;;; Collect all the symbols in a list.
- (loop for i in '(bird 3 4 turtle (1 . 4) horse cat)
- when (symbolp i) collect i)
- => (BIRD TURTLE HORSE CAT)
-
- ;;; Collect and return odd numbers.
- (loop for i from 1 to 10
- if (oddp i) collect i)
- => (1 3 5 7 9)
-
- ;;; Collect items into local variable, but don't return them.
- (loop for i in '(a b c d) by #'cddr
- collect i into my-list
- finally (print my-list)) `;Prints 1 line
- (A C)
- => NIL
-
- [Loop Clause]
- append expr [into var]
- appending expr [into var]
- nconc expr [into var]
- nconcing expr [into var]
-
- These constructs are similar to collect except that the values of the specified
- expression must be lists.
-
- The append keyword causes its list values to be concatenated into a single
- list, as if they were arguments to the Common Lisp function append.
-
- The nconc keyword causes its list values to be concatenated into a single list,
- as if they were arguments to the Common Lisp function nconc. Note that the
- nconc keyword destructively modifies its argument lists.
-
- The argument var is set to the list of concatenated values; if you specify var,
- the loop does not return the final list automatically. The var argument is
- bound as if by the construct with. You cannot specify a data type for var; it
- must be of type list.
-
- Examples:
-
- ;;; Use APPEND to concatenate some sublists.
- (loop for x in '((a) (b) ((c)))
- append x)
- => (A B (C))
-
- ;;; NCONC some sublists together. Note that only lists
- ;;; made by the call to LIST are modified.
- (loop for i upfrom 0
- as x in '(a b (c))
- nconc (if (evenp i) (list x) '()))
- => (A (C))
-
- [Loop Clause]
- count expr [into var] [type-spec]
- counting expr [into var] [type-spec]
-
- The count construct counts the number of times that the specified expression
- has a non-nil value.
-
- The argument var accumulates the number of occurrences; if var is specified,
- the loop does not return the final count automatically. The var argument is
- bound as if by the construct with.
-
- If into var is used, the optional type-spec argument specifies a data type for
- var. If there is no into variable, the optional type-spec argument applies to
- the internal variable that is keeping the count. In either case it is an error
- to specify a non-numeric data type. The default type is
- implementation-dependent, but it must be a subtype of (or integer float).
-
- Example:
-
- (loop for i in '(a b nil c nil d e)
- count i)
- => 5
-
- [Loop Clause]
- sum expr [into var] [type-spec]
- summing expr [into var] [type-spec]
-
- The sum construct forms a cumulative sum of the values of the specified
- expression at each iteration.
-
- The argument var is used to accumulate the sum; if var is specified, the loop
- does not return the final sum automatically. The var argument is bound as if by
- the construct with.
-
- If into var is used, the optional type-spec argument specifies a data type for
- var. If there is no into variable, the optional type-spec argument applies to
- the internal variable that is keeping the sum. In either case it is an error to
- specify a non-numeric data type. The default type is implementation-dependent,
- but it must be a subtype of number.
-
- Examples:
-
- ;;; Sum the elements of a list.
-
- (loop for i fixnum in '(1 2 3 4 5)
- sum i)
- => 15
-
- ;;; Sum a function of elements of a list.
-
- (setq series
- '(1.2 4.3 5.7))
- => (1.2 4.3 5.7)
-
- (loop for v in series
- sum (* 2.0 v))
- => 22.4
-
- [Loop Clause]
- maximize expr [into var] [type-spec]
- maximizing expr [into var] [type-spec]
- minimize expr [into var] [type-spec]
- minimizing expr [into var] [type-spec]
-
- The maximize construct compares the value of the specified expression obtained
- during the first iteration with values obtained in successive iterations. The
- maximum value encountered is determined and returned. If the loop never
- executes the body, the returned value is not meaningful.
-
- The minimize construct is similar to maximize; it determines and returns the
- minimum value.
-
- The argument var accumulates the maximum or minimum value; if var is specified,
- the loop does not return the maximum or minimum automatically. The var argument
- is bound as if by the construct with.
-
- If into var is used, the optional type-spec argument specifies a data type for
- var. If there is no into variable, the optional type-spec argument applies to
- the internal variable that is keeping the intermediate result. In either case
- it is an error to specify a non-numeric data type. The default type is
- implementation-dependent, but it must be a subtype of (or integer float).
-
- Examples:
-
- (loop for i in '(2 1 5 3 4)
- maximize i)
- => 5
-
- (loop for i in '(2 1 5 3 4)
- minimize i)
- => 1
-
- ;;; In this example, FIXNUM applies to the internal
- ;;; variable that holds the maximum value.
-
- (setq series '(1.2 4.3 5.7))
- => (1.2 4.3 5.7)
-
- (loop for v in series
- maximize (round v) fixnum)
- => 6
-
- ;;; In this example, FIXNUM applies to the variable RESULT.
-
- (loop for v float in series
- minimize (round v) into result fixnum
- finally (return result))
- => 1
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.9. Variable Initializations
-
- [change_begin]
- A local loop variable is one that exists only when the Loop Facility is
- invoked. At that time, the variables are declared and are initialized to some
- value. These local variables exist until loop iteration terminates, at which
- point they cease to exist. Implicitly variables are also established by
- iteration control clauses and the into preposition of accumulation clauses.
-
- The loop keyword with designates a loop clause that allows you to declare and
- initialize variables that are local to a loop. The variables are initialized
- one time only; they can be initialized sequentially or in parallel.
-
- By default, the with construct initializes variables sequentially; that is, one
- variable is assigned a value before the next expression is evaluated. However,
- by using the loop keyword and to join several with clauses, you can force
- initializations to occur in parallel; that is, all of the specified expressions
- are evaluated, and the results are bound to the respective variables
- simultaneously.
-
- Use sequential binding for making the initialization of some variables depend
- on the values of previously bound variables. For example, suppose you want to
- bind the variables a, b, and c in sequence:
-
- (loop with a = 1
- with b = (+ a 2)
- with c = (+ b 3)
- with d = (+ c 4)
- return (list a b c d))
- => (1 3 6 10)
-
- The execution of the preceding loop is equivalent to the execution of the
- following code:
-
- (let* ((a 1)
- (b (+ a 2))
- (c (+ b 3))
- (d (+ c 4)))
- (block nil
- (tagbody
- next-loop (return (list a b c d))
- (go next-loop)
- end-loop)))
-
- If you are not depending on the value of previously bound variables for the
- initialization of other local variables, you can use parallel bindings as
- follows:
-
- (loop with a = 1
- and b = 2
- and c = 3
- and d = 4
- return (list a b c d))
- => (1 2 3 4)
-
- The execution of the preceding loop is equivalent to the execution of the
- following code:
-
- (let ((a 1)
- (b 2)
- (c 3)
- (d 4))
- (block nil
- (tagbody
- next-loop (return (list a b c))
- (go next-loop)
- end-loop)))
-
- [Loop Clause]
- with var [type-spec] [= expr] {and var [type-spec] [= expr]}*
-
- The with construct initializes variables that are local to a loop. The
- variables are initialized one time only.
-
- If the optional type-spec argument is specified for any variable var, but there
- is no related expression expr to be evaluated, var is initialized to an
- appropriate default value for its data type. For example, for the data types t,
- number, and float, the default values are nil, 0, and 0.0, respectively. It is
- an error to specify a type-spec argument for var if the related expression
- returns a value that is not of the specified type. The optional and clause
- forces parallel rather than sequential initializations.
-
- Examples:
-
- ;;; These bindings occur in sequence.
- (loop with a = 1
- with b = (+ a 2)
- with c = (+ b 3)
- with d = (+ c 4)
- return (list a b c d))
- => (1 3 6 10)
-
- ;;; These bindings occur in parallel.
- (setq a 5 b 10 c 1729)
- (loop with a = 1
- and b = (+ a 2)
- and c = (+ b 3)
- and d = (+ c 4)
- return (list a b c d))
- => (1 7 13 1733)
-
- ;;; This example shows a shorthand way to declare
- ;;; local variables that are of different types.
- (loop with (a b c) (float integer float)
- return (format nil "~A ~A ~A" a b c))
- => "0.0 0 0.0"
-
- ;;; This example shows a shorthand way to declare
- ;;; local variables that are of the same type.
- (loop with (a b c) float
- return (format nil "~A ~A ~A" a b c))
- => "0.0 0.0 0.0"
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.10. Conditional Execution
-
- [change_begin]
- The loop keywords if, when, and unless designate constructs that are useful
- when you want some loop clauses to operate under a specified condition.
-
- If the specified condition is true, the succeeding loop clause is executed. If
- the specified condition is not true, the succeeding clause is skipped, and
- program control moves to the clause that follows the loop keyword else. If the
- specified condition is not true and no else clause is specified, the entire
- conditional construct is skipped. Several clauses can be connected into one
- compound clause with the loop keyword and. The end of the conditional clause
- can be marked with the keyword end.
-
- [Loop Clause]
-
- if expr clause {and clause}*
- [else clause {and clause}*] [end]
- when expr clause {and clause}*
- [else clause {and clause}*] [end]
- unless expr clause {and clause}*
- [else clause {and clause}*] [end]
-
- The constructs when and if allow conditional execution of loop clauses. These
- constructs are synonyms and can be used interchangeably. [Compare this to the
- macro when, which does not allow an ``else'' part.-GLS]
-
- If the value of the test expression expr is non-nil, the expression clause1 is
- evaluated. If the test expression evaluates to nil and an else construct is
- specified, the statements that follow the else are evaluated; otherwise,
- control passes to the next clause.
-
- The unless construct is equivalent to when (not expr) and if (not expr). If the
- value of the test expression expr is nil, the expression clause1 is evaluated.
- If the test expression evaluates to non-nil and an else construct is specified,
- the statements that follow the else are evaluated; otherwise, control passes to
- the next clause. [Compare this to the macro unless, which does not allow an
- ``else'' part-or do I mean a ``then'' part?! Ugh. To prevent confusion, I
- strongly recommend as a matter of style that else not be used with unless loop
- clauses.-GLS]
-
- The clause arguments must be either accumulation, unconditional, or conditional
- clauses (see section 26.3.2). Clauses that follow the test expression can be
- grouped by using the loop keyword and to produce a compound clause.
-
- The loop keyword it can be used to refer to the result of the test expression
- in a clause. If multiple clauses are connected with and, the it construct must
- be used in the first clause in the block. Since it is a loop keyword, it may
- not be used as a local variable within a loop.
-
- If when or if clauses are nested, each else is paired with the closest
- preceding when or if construct that has no associated else.
-
- The optional loop keyword end marks the end of the clause. If this keyword is
- not specified, the next loop keyword marks the end. You can use end to
- distinguish the scoping of compound clauses.
-
- ;;; Group conditional clauses into a block.
- (loop for i in numbers-list
- when (oddp i)
- do (print i)
- and collect i into odd-numbers
- and do (terpri)
- else ;I is even
- collect i into even-numbers
- finally
- (return (values odd-numbers even-numbers)))
-
- ;;; Collect numbers larger than 3.
- (loop for i in '(1 2 3 4 5 6)
- when (and (> i 3) i)
- collect it) ;it refers to (and (> i 3) i)
- => (4 5 6)
-
- ;;; Find a number in a list.
- (loop for i in '(1 2 3 4 5 6)
- when (and (> i 3) i)
- return it)
- => 4
-
- ;;; The preceding example is similar to the following one.
- (loop for i in '(1 2 3 4 5 6)
- thereis (and (> i 3) i))
- => 4
-
- ;;; An example of using UNLESS with ELSE (yuk).`-GLS
- (loop for turtle in teenage-mutant-ninja-turtles do
- (loop for x in '(joker brainiac shredder krazy-kat)
- unless (evil x)
- do (eat (make-pizza :anchovies t))
- else unless (and (eq x 'shredder) (attacking-p x))
- do (cut turtle slack);When the evil Shredder attacks,
- else (fight turtle x)));those turtle boys don't cut no slack
-
- ;;; Nest conditional clauses.
- (loop for i in list
- when (numberp i)
- when (bignump i)
- collect i into big-numbers
- else ;Not (bignump i)
- collect i into other-numbers
- else ;Not (numberp i)
- when (symbolp i)
- collect i into symbol-list
- else ;Not (symbolp i)
- (error "found a funny value in list ~S, value ~S~%"
- "list i))
-
- ;;; Without the END marker, the last AND would apply to the
- ;;; inner IF rather than the outer one.
- (loop for x from 0 to 3
- do (print x)
- if (zerop (mod x 2))
- do (princ " a")
- and if (zerop (floor x 2))
- do (princ " b")
- end
- and do (princ " c"))
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.11. Unconditional Execution
-
- [change_begin]
- The loop construct do (or doing) takes one or more expressions and simply
- evaluates them in order.
-
- The loop construct return takes one expression and returns its value. It is
- equivalent to the clause do (return value).
-
- [Loop Clause]
- do {expr}*
- doing {expr}*
-
- The do construct simply evaluates the specified expressions wherever they occur
- in the expanded form of loop.
-
- The expr argument can be any non-atomic Common Lisp form. Each expr is
- evaluated in every iteration.
-
- The constructs do, initially, and finally are the only loop keywords that take
- an arbitrary number of forms and group them as if using an implicit progn.
- Because every loop clause must begin with a loop keyword, you would use the
- keyword do when no control action other than execution is required.
-
- Examples:
-
- ;;; Print some numbers.
- (loop for i from 1 to 5
- do (print i)) `;Prints 5 lines
-
-
-
-
-
- => NIL
-
- ;;; Print numbers and their squares.
- ;;; The DO construct applies to multiple forms.
- (loop for i from 1 to 4
- do (print i)
- (print (* i i))) `;Prints 8 lines
-
-
-
-
-
-
-
- 16
- => NIL
-
- [Loop Clause]
- return expr
-
- The return construct terminates a loop and returns the value of the specified
- expression as the value of the loop. This construct is similar to the Common
- Lisp special form return-from and the Common Lisp macro return.
-
- The Loop Facility supports the return construct for backward compatibility with
- older loop implementations. The return construct returns immediately and does
- not execute any finally clause that is given.
-
- Examples:
-
- ;;; Signal an exceptional condition.
- (loop for item in '(1 2 3 a 4 5)
- when (not (numberp item))
- return (cerror "enter new value"
- "non-numeric value: ~s"
- item)) `;Signals an error
- >>Error: non-numeric value: A
-
- ;;; The previous example is equivalent to the following one.
- (loop for item in '(1 2 3 a 4 5)
- when (not (numberp item))
- do (return
- (cerror "enter new value"
- "non-numeric value: ~s"
- item))) `;Signals an error
- >>Error: non-numeric value: A
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.12. Miscellaneous Features
-
- [change_begin]
- The Loop Facility provides the named construct to name a loop so that the
- Common Lisp special form return-from can be used.
-
- The loop keywords initially and finally designate loop constructs that cause
- expressions to be evaluated before and after the loop body, respectively.
-
- The code for any initially clauses is collected into one progn in the order in
- which the clauses appeared in the loop. The collected code is executed once in
- the loop prologue after any implicit variable initializations.
-
- The code for any finally clauses is collected into one progn in the order in
- which the clauses appeared in the loop. The collected code is executed once in
- the loop epilogue before any implicit values are returned from the accumulation
- clauses. Explicit returns in the loop body, however, will exit the loop without
- executing the epilogue code.
-
- [change_end]
- -------------------------------------------------------------------------------
-
- * Data Types
- * Destructuring
-
- -------------------------------------------------------------------------------
-
- 26.12.1. Data Types
-
- [change_begin]
- Many loop constructs take a type-spec argument that allows you to specify
- certain data types for loop variables. While it is not necessary to specify a
- data type for any variable, by doing so you ensure that the variable has a
- correctly typed initial value. The type declaration is made available to the
- compiler for more efficient loop expansion. In some implementations, fixnum and
- float declarations are especially useful; the compiler notices them and emits
- more efficient code.
-
- The type-spec argument has the following syntax:
-
- type-spec ::= of-type d-type-spec
- d-type-spec ::= type-specifier | (d-type-spec . d-type-spec)
-
- A type-specifier in this syntax can be any Common Lisp type specifier. The
- d-type-spec argument is used for destructuring, as described in section
- 26.12.2. If the d-type-spec argument consists solely of the types fixnum,
- float, t, or nil, the of-type keyword is optional. The of-type construct is
- optional in these cases to provide backward compatibility; thus the following
- two expressions are the same:
-
- ;;; This expression uses the old syntax for type specifiers.
- (loop for i fixnum upfrom 3 ...)
- ;;; This expression uses the new syntax for type specifiers.
- (loop for i of-type fixnum upfrom 3 ...)
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 26.12.2. Destructuring
-
- [change_begin]
- Destructuring allows you to bind a set of variables to a corresponding set of
- values anywhere that you can normally bind a value to a single variable. During
- loop expansion, each variable in the variable list is matched with the values
- in the values list. If there are more variables in the variable list than there
- are values in the values list, the remaining variables are given a value of
- nil. If there are more values than variables listed, the extra values are
- discarded.
-
- Suppose you want to assign values from a list to the variables a, b, and c. You
- could use one for clause to bind the variable numlist to the car of the
- specified expression, and then you could use another for clause to bind the
- variables a, b, and c sequentially.
-
- ;;; Collect values by using FOR constructs.
- (loop for numlist in '((1 2 4.0) (5 6 8.3) (8 9 10.4))
- for a integer = (first numlist)
- and for b integer = (second numlist)
- and for c float = (third numlist)
- collect (list c b a))
- => ((4.0 2 1) (8.3 6 5) (10.4 9 8))
-
- Destructuring makes this process easier by allowing the variables to be bound
- in parallel in each loop iteration. You can declare data types by using a list
- of type-spec arguments. If all the types are the same, you can use a shorthand
- destructuring syntax, as the second example following illustrates.
-
- ;;; Destructuring simplifies the process.
- (loop for (a b c) (integer integer float) in
- '((1 2 4.0) (5 6 8.3) (8 9 10.4))
- collect (list c b a)))
- => ((4.0 2 1) (8.3 6 5) (10.4 9 8))
-
- ;;; If all the types are the same, this way is even simpler.
- (loop for (a b c) float in
- '((1.0 2.0 4.0) (5.0 6.0 8.3) (8.0 9.0 10.4))
- collect (list c b a))
- => ((4.0 2.0 1.0) (8.3 6.0 5.0) (10.4 9.0 8.0))
-
- If you use destructuring to declare or initialize a number of groups of
- variables into types, you can use the loop keyword and to simplify the process
- further.
-
- ;;; Initialize and declare variables in parallel
- ;;; by using the AND construct.
- (loop with (a b) float = '(1.0 2.0)
- and (c d) integer = '(3 4)
- and (e f)
- return (list a b c d e f))
- => (1.0 2.0 3 4 NIL NIL)
-
- A data type specifier for a destructuring pattern is a tree of type specifiers
- with the same shape as the tree of variables, with the following exceptions:
-
- * When aligning the trees, an atom in the type specifier tree that matches
- a cons in the variable tree declares the same type for each variable.
-
- * A cons in the type specifier tree that matches an atom in the variable
- tree is a non-atomic type specifer.
-
- ;;; Declare X and Y to be of type VECTOR and FIXNUM, respectively.
- (loop for (x y) of-type (vector fixnum) in my-list do ...)
-
- If nil is used in a destructuring list, no variable is provided for its place.
-
- (loop for (a nil b) = '(1 2 3)
- do (return (list a b)))
- => (1 3)
-
- Note that nonstandard lists can specify destructuring.
-
- (loop for (x . y) = '(1 . 2)
- do (return y))
- => 2
-
- (loop for ((a . b) (c . d))
- of-type ((float . float) (integer . integer))
- in '(((1.2 . 2.4) (3 . 4)) ((3.4 . 4.6) (5 . 6)))
- collect (list a b c d))
- => ((1.2 2.4 3 4) (3.4 4.6 5 6))
-
- [It is worth noting that the destructuring facility of loop predates, and
- differs in some details from, that of destructuring-bind, an extension that has
- been provided by many implementors of Common Lisp.-GLS]
-
- [Loop Clause]
- initially {expr}*
- finally [do | doing] {expr}*
- finally return expr
-
- The initially construct causes the specified expression to be evaluated in the
- loop prologue, which precedes all loop code except for initial settings
- specified by constructs with, for, or as. The finally construct causes the
- specified expression to be evaluated in the loop epilogue after normal
- iteration terminates.
-
- The expr argument can be any non-atomic Common Lisp form.
-
- Clauses such as return, always, never, and thereis can bypass the finally
- clause.
-
- The Common Lisp macro return (or the return loop construct) can be used after
- finally to return values from a loop. The evaluation of the return form inside
- the finally clause takes precedence over returning the accumulation from
- clauses specified by such keywords as collect, nconc, append, sum, count,
- maximize, and minimize; the accumulation values for these pre-empted clauses
- are not returned by the loop if return is used.
-
- The constructs do, initially, and finally are the only loop keywords that take
- an arbitrary number of (non-atomic) forms and group them as if by using an
- implicit progn.
-
- Examples:
-
- ;;; This example parses a simple printed string representation
- ;;; from BUFFER (which is itself a string) and returns the
- ;;; index of the closing double-quote character.
-
- (loop initially (unless (char= (char buffer 0) #\")
- (loop-finish))
- for i fixnum from 1 below (string-length buffer)
- when (char= (char buffer i) #\")
- return i)
-
- ;;; The FINALLY clause prints the last value of I.
- ;;; The collected value is returned.
-
- (loop for i from 1 to 10
- when (> i 5)
- collect i
- finally (print i)) `;Prints 1 line
- 11
- => (6 7 8 9 10)
-
- ;;; Return both the count of collected numbers
- ;;; as well as the numbers themselves.
-
- (loop for i from 1 to 10
- when (> i 5)
- collect i into number-list
- and count i into number-count
- finally (return (values number-count number-list)))
- => 5 and (6 7 8 9 10)
-
- [Loop Clause]
- named name
-
- The named construct allows you to assign a name to a loop construct so that you
- can use the Common Lisp special form return-from to exit the named loop.
-
- Only one name may be assigned per loop; the specified name becomes the name of
- the implicit block for the loop.
-
- If used, the named construct must be the first clause in the loop expression,
- coming right after the word loop.
-
- Example:
-
- ;;; Just name and return.
- (loop named max
- for i from 1 to 10
- do (print i)
- do (return-from max 'done)) `;Prints 1 line
-
- => DONE
-
- [change_end]
-
- -------------------------------------------------------------------------------
-
-
-
-
-